package com.example.pt.controller;

import com.dampcake.bencode.Bencode;
import com.dampcake.bencode.Type;
import com.example.pt.dto.ApiResponse;
import com.example.pt.entity.Peer;
import com.example.pt.entity.Torrent;
import com.example.pt.entity.User;
import com.example.pt.repository.PeerRepository;
import com.example.pt.repository.TorrentRepository;
import com.example.pt.repository.UserRepository;
import com.example.pt.service.TorrentService;
import com.example.pt.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
import com.dampcake.bencode.Bencode;
import com.dampcake.bencode.Type;
import java.util.Map;

@RestController
@RequestMapping("/api/torrents")
public class TorrentController {

    @Autowired
    private TorrentService torrentService;
    @Autowired
    private UserService userService;

    @GetMapping("/recommend")
    public ApiResponse<List<Torrent>> getRecommendedTorrents() {
        return ApiResponse.success(torrentService.getRecommendedTorrents());
    }

    // 查看详情
    @PostMapping("/detail")
    public ApiResponse<Torrent> getDiscountedTorrentByUserAndId(@RequestBody Map<String, Long> params) {
        Long userId = params.get("user_id");
        Long torrentId = params.get("id");

        if (userId == null || torrentId == null) {
            return ApiResponse.fail("参数不完整");
        }

        User currentUser = userService.findById(userId);
        Optional<Torrent> optionalTorrent = torrentService.getDetailById(torrentId);
        if (optionalTorrent.isEmpty()) {
            return ApiResponse.fail("种子不存在");
        }

        Torrent torrent = optionalTorrent.get();

        // 查促销列表，判断是否有折扣
        List<Torrent> discountList = torrentService.getDiscountedTorrents();

        float discount = 1.0f;
        for (Torrent t : discountList) {
            if (t.getId().equals(torrentId)) {
                discount = t.getDiscount() == null ? 1.0f : t.getDiscount();
                break;
            }
        }

        // 根据用户等级额外折扣
        if (currentUser != null && currentUser.getLevel() != null) {
            switch (currentUser.getLevel()) {
                case "Elite User" -> discount *= 0.6f;
                case "Power User" -> discount *= 0.8f;
                default -> { }
            }
        }

        torrent.setDiscount(discount);

        return ApiResponse.success(torrent);
    }

    // 搜索种子
    @PostMapping("/search")
    public ApiResponse<List<Torrent>> searchTorrents(@RequestBody Map<String, String> request) {
        String name = request.get("name");
        Long userId = request.containsKey("user_id") ? Long.valueOf(request.get("user_id")) : null;

        System.out.println("搜索关键词: " + name);

        // 搜索匹配的种子列表
        List<Torrent> result = torrentService.searchTorrents(name);

        // 获取当前用户信息
        User currentUser = userId != null ? userService.findById(userId) : null;

        // 获取当前正在促销的种子列表
        List<Torrent> discountList = torrentService.getDiscountedTorrents();
        Set<Long> discountIds = discountList.stream().map(Torrent::getId).collect(Collectors.toSet());
        Map<Long, Float> discountMap = discountList.stream()
                .collect(Collectors.toMap(
                        Torrent::getId,
                        t -> t.getDiscount() != null ? t.getDiscount() : 1.0f,
                        (v1, v2) -> v1  // 遇到重复 key，保留第一个值
                ));


        // 遍历搜索结果并设置折扣
        for (Torrent torrent : result) {
            float discount = 1.0f;

            // 查促销列表，判断是否有折扣
            if (discountIds.contains(torrent.getId())) {
                discount = discountMap.get(torrent.getId());
            }

            // 根据用户等级额外折扣
            if (currentUser != null && currentUser.getLevel() != null) {
                switch (currentUser.getLevel()) {
                    case "Elite User" -> discount *= 0.6f;
                    case "Power User" -> discount *= 0.8f;
                    default -> { }
                }
            }

            torrent.setDiscount(discount);
        }
        return ApiResponse.success(result);
    }

    //促销
//    @GetMapping("/promotions")
//    public ApiResponse<List<Torrent>> getDiscountedTorrents() {
//        return ApiResponse.success(torrentService.getDiscountedTorrents());
//    }
    @GetMapping("/promotions/{user_id}")
    public ApiResponse<List<Torrent>> getDiscountedTorrents(@PathVariable Long user_id) {
        User currentUser = userService.findById(user_id);
        List<Torrent> discountList = torrentService.getDiscountedTorrents();

        float levelMultiplier = 1.0f;
        if (currentUser != null && currentUser.getLevel() != null) {
            switch (currentUser.getLevel()) {
                case "Elite User" -> levelMultiplier = 0.6f;
                case "Power User" -> levelMultiplier = 0.8f;
                default -> levelMultiplier = 1.0f;
            }
        }

        for (Torrent t : discountList) {
            if (t.getDiscount() == null) {
                t.setDiscount(1.0f);
            }
            t.setDiscount(t.getDiscount() * levelMultiplier);
        }

        return ApiResponse.success(discountList);
    }



    private final Bencode bencode = new Bencode(StandardCharsets.UTF_8);

    private final TorrentRepository torrentRepository;
    private final UserRepository userRepository;

    @Value("${tracker.base.url}")
    private String trackerBaseUrl;

    @Autowired
    public TorrentController(TorrentService torrentService, TorrentRepository torrentRepository,
                             UserRepository userRepository) {
        this.torrentService = torrentService;
        this.torrentRepository = torrentRepository;
        this.userRepository = userRepository;
    }

    //用户上传文件
    @PostMapping(path = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseEntity<?> uploadTorrent(
            @RequestParam("name") String name,
            @RequestParam("category") String category,
            @RequestParam("description") String description,
            @RequestParam("currentUserId") Long currentUserId,
            @RequestParam("torrentFile") MultipartFile torrentFile) throws IOException, NoSuchAlgorithmException {

        // 1. 验证用户
        Optional<User> user = userRepository.findById(currentUserId);
        if (user.isEmpty()) {
            return ResponseEntity.badRequest().body("User not found");
        }

        // 2. 读取.torrent文件内容
        byte[] torrentBytes = torrentFile.getBytes();

        // 3. 解析.torrent文件
        Map<String, Object> torrentData;
        try (ByteArrayInputStream bis = new ByteArrayInputStream(torrentBytes)) {
            torrentData = bencode.decode(torrentBytes, Type.DICTIONARY);
        }

        // 4. 计算info_hash
        Map<String, Object> info = (Map<String, Object>) torrentData.get("info");

        // 确保字典键按字典序排序
        Map<String, Object> sortedInfo = new TreeMap<>(info);

        // 特殊处理files列表中的字典排序
        if (sortedInfo.containsKey("files")) {
            List<Map<String, Object>> files = (List<Map<String, Object>>) sortedInfo.get("files");
            List<Map<String, Object>> sortedFiles = new ArrayList<>();
            for (Map<String, Object> file : files) {
                sortedFiles.add(new TreeMap<>(file));
            }
            sortedInfo.put("files", sortedFiles);
        }

        // 确保pieces字段直接使用原始字节
        if (info.containsKey("pieces")) {
            sortedInfo.put("pieces", info.get("pieces"));  // 保持二进制格式
        }

        Bencode strictBencode = new Bencode(StandardCharsets.ISO_8859_1);
        byte[] infoBytes = strictBencode.encode(sortedInfo); // 使用现有的encode方法
        String infoHash = calculateSHA1(infoBytes);

        // 5. 检查是否已存在
        if (torrentRepository.existsById(infoHash)) {
            return ResponseEntity.badRequest().body("Torrent already exists");
        }

        // 6. 创建Torrent实体
        Torrent torrent = new Torrent();
        torrent.setInfoHash(infoHash);
        torrent.setName(name);
        //torrent.setDescription(description);
        torrent.setCategory(category);

        // 处理文件大小
        if (info.containsKey("length")) {
            // 单文件
            Object lengthObj = info.get("length");
            if (lengthObj instanceof Number) {
                torrent.setCost(((Number) lengthObj).floatValue());
            } else {
                torrent.setCost(0f); // 或者你想要的默认值
            }
        } else if (info.containsKey("files")) {
            // 多文件
            long totalSize = ((List<Map<String, Object>>) info.get("files")).stream()
                    .mapToLong(file -> ((Number) file.get("length")).longValue())
                    .sum();
            torrent.setCost((float) totalSize);
        }

//        torrent.setUploadedBy(user.get());
//        torrent.setUploadedAt(LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault()));

        torrent.setUploadedBy(user.get());
        torrent.setUploadedAt(LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault()));
        torrent.setFile(torrentBytes); // <-- 保存.torrent文件为二进制到数据库


        // 7. 保存.torrent文件
        Path torrentDir = Paths.get("D:/PT/pt/upload");
        Files.createDirectories(torrentDir);
        Path torrentPath = torrentDir.resolve(infoHash + ".torrent");
        Files.write(torrentPath, torrentBytes);

        System.out.println("Original info: " + info);
        System.out.println("Sorted info: " + sortedInfo);
        System.out.println("Bencoded info bytes: " + Arrays.toString(infoBytes));
        System.out.println("Calculated infoHash: " + infoHash);

        // 8. 保存到数据库
        torrentRepository.save(torrent);

        return ResponseEntity.ok(torrent);
    }

//    private String calculateSHA1(byte[] data) throws NoSuchAlgorithmException {
//        MessageDigest digest = MessageDigest.getInstance("SHA-1");
//        byte[] hash = digest.digest(data);
//        return Base64.getUrlEncoder().withoutPadding().encodeToString(hash);
//    }

    private String calculateSHA1(byte[] data) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance("SHA-1");
        byte[] hash = digest.digest(data);
        return bytesToHex(hash); // 改为返回16进制字符串
    }

    // 字节数组转16进制工具方法
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString().toLowerCase(); // BitTorrent规范使用小写
    }

    //暂时没用
    @PostMapping("/update-stats")
    public ResponseEntity<?> updateStats(
            @RequestParam String username,
            @RequestParam String infoHash,
            @RequestParam long uploaded,
            @RequestParam long downloaded
    ) {
        // 获取用户和种子逻辑
        Optional<User> user = userRepository.findByUsername(username);
        if (user.isEmpty()) {
            return ResponseEntity.badRequest().body("User not found");
        }

        Optional<Torrent> torrent = torrentRepository.findByInfoHash(infoHash);
        if (torrent.isEmpty()) {
            return ResponseEntity.badRequest().body("Torrent not found");
        }
//        torrentService.updateStats(user.get(), torrent.get(), uploaded, downloaded);
        return ResponseEntity.ok(user);
    }

    @GetMapping
    public ResponseEntity<?> getAllTorrents() {
        return ResponseEntity.ok(torrentRepository.findAll());
    }

    @Autowired
    private PeerRepository peerRepository;
//    @GetMapping("/{id}/download")
//    public ResponseEntity<byte[]> downloadTorrentFile(
//            @PathVariable String infoHash,
//            @RequestParam String passkey) throws IOException {
//        // 验证infoHash格式
//        if (!infoHash.matches("^[0-9a-f]{40}$")) {
//            return ResponseEntity.badRequest().build();
//        }
//
//        // 1. 验证用户权限
//        Optional<User> user = userRepository.findByPasskey(passkey);
//        if (user.isEmpty()) {
//            return ResponseEntity.status(403).build();
//        }
//
//        // 2. 检查种子是否存在
//        Optional<Torrent> torrentOpt = torrentRepository.findById(infoHash);
//        if (torrentOpt.isEmpty()) {
//            return ResponseEntity.notFound().build();
//        }
//
//        // 1. 读取原始文件字节
//        Path torrentPath = Paths.get("D:/PT/pt/upload", infoHash + ".torrent");
//        byte[] originalBytes = Files.readAllBytes(torrentPath);
//
//        // 2. 直接替换 announce URL（字节操作）
//        String oldAnnounce = "http://10.60.31.105:9966/tracker/announce";
//        String newAnnounce = trackerBaseUrl + "/announce?passkey=" + passkey;
//
//        // 修改 announce URL（关键修改）
//        String announceUrl = trackerBaseUrl.endsWith("/") ?
//                trackerBaseUrl + "announce?passkey=" + passkey :
//                trackerBaseUrl + "/announce?passkey=" + passkey;
//
//        // 3. 构建替换模式（格式：d8:announce32:http://...）
//        String oldPattern = "d8:announce" + oldAnnounce.length() + ":" + oldAnnounce;
//        String newPattern = "d8:announce" + newAnnounce.length() + ":" + newAnnounce;
//
//        // 4. 执行替换
//        String torrentStr = new String(originalBytes, StandardCharsets.ISO_8859_1);
//        byte[] modifiedBytes = torrentStr.replace(oldPattern, newPattern)
//                .getBytes(StandardCharsets.ISO_8859_1);
//
//        // 5. 验证修改
//        if (Arrays.equals(originalBytes, modifiedBytes)) {
//            throw new IOException("Failed to modify torrent file");
//        }
//
//
//        Path fileDir = Paths.get("D:/PT/pt/download");
//        Files.createDirectories(fileDir);
//        Path filePath = fileDir.resolve(infoHash + ".torrent");
//        Files.write(filePath, modifiedBytes);
//
//        Peer peer = new Peer();
//        peer.setUser(user.get());
//        peer.setTorrent(torrentOpt.get());
//        peerRepository.save(peer);
//
//
//        // 9. 返回修改后的.torrent文件
//        return ResponseEntity.ok()
//                .header("Content-Disposition", "attachment; filename=\"" + infoHash + ".torrent\"")
//                .body(modifiedBytes);
//    }

//    @GetMapping("/{id}/download")
//    public ResponseEntity<byte[]> downloadTorrentFile(@PathVariable String id) throws IOException {
//        // 1. 查找种子信息
//        Optional<Torrent> torrentOpt = torrentRepository.findById(id);
//        if (torrentOpt.isEmpty()) {
//            return ResponseEntity.notFound().build();
//        }
//        Torrent torrent = torrentOpt.get();
//
//        // 2. 获取上传者用户
//        User uploader = torrent.getUploadedBy();
//        if (uploader == null || uploader.getPasskey() == null) {
//            return ResponseEntity.status(403).body(null); // 无权限或无passkey
//        }
//
//        String passkey = uploader.getPasskey();
//        String infoHash = torrent.getInfoHash();
//
//        // 3. 获取原始 .torrent 文件内容（二选一）
//        // 3.1 从数据库中取二进制
//        byte[] originalBytes = torrent.getFile();
//        if (originalBytes == null || originalBytes.length == 0) {
//            return ResponseEntity.status(500).body(null);
//        }
//
//        // 4. 替换 announce URL
//        String oldAnnounce = "http://192.168.43.26:9966/tracker/announce";
//        String newAnnounce = trackerBaseUrl.endsWith("/") ?
//                trackerBaseUrl + "announce?passkey=" + passkey :
//                trackerBaseUrl + "/announce?passkey=" + passkey;
//
//        String oldPattern = "d8:announce" + oldAnnounce.length() + ":" + oldAnnounce;
//        String newPattern = "d8:announce" + newAnnounce.length() + ":" + newAnnounce;
//
//        String torrentStr = new String(originalBytes, StandardCharsets.ISO_8859_1);
//        byte[] modifiedBytes = torrentStr.replace(oldPattern, newPattern)
//                .getBytes(StandardCharsets.ISO_8859_1);
//
//        // 5. 校验替换成功
//        if (Arrays.equals(originalBytes, modifiedBytes)) {
//            return ResponseEntity.status(500).body(null);
//        }
//
//        // 6. 保存下载记录（可选）
//        Peer peer = new Peer();
//        peer.setUser(uploader);
//        peer.setTorrent(torrent);
//        peerRepository.save(peer);
//
//        // 7. 返回文件
//        return ResponseEntity.ok()
//                .header("Content-Disposition", "attachment; filename=\"" + infoHash + ".torrent\"")
//                .body(modifiedBytes);
//    }

    @PostMapping("/download")
    public ResponseEntity<byte[]> downloadTorrentFile(@RequestBody Map<String, Object> payload) throws IOException {
        Object torrentIdObj = payload.get("id");
        Long torrentId;
        if (torrentIdObj instanceof Number) {
            torrentId = ((Number) torrentIdObj).longValue();
        } else if (torrentIdObj instanceof String) {
            torrentId = Long.valueOf((String) torrentIdObj);
        } else {
            return ResponseEntity.badRequest().build();
        }

        Object userIdObj = payload.get("user_id");
        Long userId;
        if (userIdObj instanceof Number) {
            userId = ((Number) userIdObj).longValue();
        } else if (userIdObj instanceof String) {
            userId = Long.valueOf((String) userIdObj);
        } else {
            return ResponseEntity.badRequest().build();
        }

        Optional<Torrent> torrentOpt = torrentRepository.findById(torrentId);
        if (torrentOpt.isEmpty()) {
            return ResponseEntity.status(404).body("Torrent not found".getBytes());
        }
        Torrent torrent = torrentOpt.get();

        Optional<User> userOpt = userRepository.findById(userId);
        if (userOpt.isEmpty()) {
            return ResponseEntity.status(403).body("User not found".getBytes());
        }
        User user = userOpt.get();
        String passkey = user.getPasskey();
        System.out.println(passkey);
        if (passkey == null || passkey.isBlank()) {
            return ResponseEntity.status(403).body("User has no passkey".getBytes());
        }

        String infoHash = torrent.getInfoHash();
        System.out.println(infoHash);
        byte[] originalBytes = torrent.getFile();
        if (originalBytes == null || originalBytes.length == 0) {
            return ResponseEntity.status(500).body("Torrent file is empty".getBytes());
        }

        String trackerBaseUrl = "http://192.168.43.26:9966/tracker";
        String newAnnounce = trackerBaseUrl.endsWith("/") ?
                trackerBaseUrl + "announce?passkey=" + passkey :
                trackerBaseUrl + "/announce?passkey=" + passkey;
        System.out.println(newAnnounce);

        // 把二进制用ISO_8859_1编码成字符串，保持字节不变
        String torrentStr = new String(originalBytes, StandardCharsets.ISO_8859_1);

        String oldAnnounce = "http://10.60.31.105:9966/tracker/announce";

        String oldPattern = "d8:announce" + oldAnnounce.length() + ":" + oldAnnounce;
        String newPattern = "d8:announce" + newAnnounce.length() + ":" + newAnnounce;


//        if (!torrentStr.contains(oldPattern)) {
//            return ResponseEntity.status(500).body("announce field not found or format mismatch".getBytes());
//        }

        String replacedStr = torrentStr.replace(oldPattern, newPattern);
        System.out.println(replacedStr);

        byte[] modifiedBytes = replacedStr.getBytes(StandardCharsets.ISO_8859_1);

        // 记录下载
        Peer peer = new Peer();
        peer.setUser(user);
        peer.setTorrent(torrent);
        peerRepository.save(peer);

        System.out.println(infoHash);
        // 返回修改后的 torrent 文件
        return ResponseEntity.ok()
                .header("Content-Disposition", "attachment; filename=\"" + infoHash + ".torrent\"")
                .body(modifiedBytes);

    }




}

